﻿using System;

using Microsoft.Office.Core;
using Microsoft.Office.Interop.PowerPoint;
using PowerPoint = Microsoft.Office.Interop.PowerPoint;
using Graph = Microsoft.Office.Interop.Graph;

using Outcoding.GraphGenerator.Entities;
using Outcoding.GraphGenerator.Util.Logging;
using Outcoding.GraphGenerator.Generator.Util;

using Presentation = Outcoding.GraphGenerator.Entities.Presentation;
using Shape=Microsoft.Office.Core.Shape;
using Slide = Outcoding.GraphGenerator.Entities.Slide;

namespace Outcoding.GraphGenerator.Generator
{
    public class Plotter2007 : IChartGenerator
    {

        #region Events

        public event SlideComposingHandler SlideComposing;

        public event SlideComposedHandler SlideComposed;

        #endregion

        #region Event Handlers

        protected void OnSlideComposing(object sender, SlideComposingEventArgs args)
        {
            string message = string.Format("Composing Slide {0} of {1}.", args.CurrentSlideIndex, args.TotalSlides);
            LogManager.Instance.LogInfo(message);
        }

        protected void OnSlideComposed(object sender, SlideComposedEventArgs args)
        {
            string message = string.Empty;

            if (args.IsComposeSuccessful)
                message = "Slide successfully composed.";
            else
                message = "Slide compose failed.";

            LogManager.Instance.LogInfo(message);
        }

        #endregion

        #region Init Methods

        private void Init()
        {
            SlideComposing += new SlideComposingHandler(OnSlideComposing);
            SlideComposed += new SlideComposedHandler(OnSlideComposed);
        }

        #endregion

        private Presentation mPresentation;

        private PowerPoint.Application mPPApplication;
        private PowerPoint.Presentations mPPPresentations;
        private PowerPoint._Presentation mPPPresentation;

        public PowerPoint.Application PPApplication
        {
            get
            {
                return mPPApplication;
            }
        }

        public PowerPoint._Presentation PPPresentation
        {
            get
            {
                return mPPPresentation;
            }
        }

        public Plotter2007(Presentation presentation)
        {
            Init();

            mPresentation = presentation;
            mPPApplication = new Microsoft.Office.Interop.PowerPoint.Application();
            string version = mPPApplication.Version;
            mPPApplication.Visible = MsoTriState.msoTrue;
            mPPPresentations = mPPApplication.Presentations;
        }

        public Plotter2007()
        {
            Init();
        }

        public void GeneratePresentation(Presentation presentation)
        {
            mPresentation = presentation;
            mPPApplication = new Microsoft.Office.Interop.PowerPoint.Application();
            mPPApplication.Visible = MsoTriState.msoTrue;
            string version = mPPApplication.Version;
            mPPPresentations = mPPApplication.Presentations;

            try
            {
                if (!System.IO.File.Exists(mPresentation.TemplatePath))
                {
                    String strPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase);
                    strPath = strPath.Substring(6);
                    mPresentation.TemplatePath = strPath + "\\Pixel.pot";
                }
                mPPPresentation = mPPPresentations.Open(mPresentation.TemplatePath, MsoTriState.msoFalse, MsoTriState.msoTrue, MsoTriState.msoTrue);
                GenerateSlides(mPresentation.Slides);
            }
            catch (Exception exc)
            {
                LogManager.Instance.LogError("Power Point Presentation could not be created.", exc);
                throw;
            }
        }

        public void GeneratePresentation()
        {
            try
            {
                if (!System.IO.File.Exists(mPresentation.TemplatePath))
                {
                    String strPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase);
                    strPath = strPath.Substring(6);
                    mPresentation.TemplatePath = strPath + "\\Pixel.pot";
                }
                mPPPresentation = mPPPresentations.Open(mPresentation.TemplatePath, MsoTriState.msoFalse, MsoTriState.msoTrue, MsoTriState.msoTrue);
                GenerateSlides(mPresentation.Slides);
            }
            catch (Exception exc)
            {
                LogManager.Instance.LogError("Power Point Presentation could not be created.", exc);
                throw;
            }
        }

        private void GenerateSlides(SlideCollection slideCollection)
        {
            System.Globalization.CultureInfo oldCI = System.Threading.Thread.CurrentThread.CurrentCulture;
            System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");

            PowerPoint.Slides objSlides = mPPPresentation.Slides;
            for (int i = 0; i < slideCollection.Count; i++)
            {
                NotifySlideComposing(i + 1, slideCollection.Count, SlideComposingEventArgs.ContentType.Unknown);
                Slide slide = slideCollection[i];
                PowerPoint._Slide objSlide = objSlides.Add(i + 1, Entities.Util.ParseEnum<PpSlideLayout>(slide.Layout));
                try
                {
                    GenerateContent(slide.Shapes, objSlide);
                }
                catch (Exception exc)
                {
                    //HACK: find a more elegant way to inform a fail case when creating slide
                    NotifySlideCompose(false);
                    throw;
                }
                NotifySlideCompose(true);
            }

            System.Threading.Thread.CurrentThread.CurrentCulture = oldCI;
        }

        private void GenerateContent(ShapeCollection shapes, PowerPoint._Slide ppSlide)
        {
            if (shapes.Count > 0)
            {
                ClearShapeSpace(ppSlide);
                foreach (Entities.Shape shape in shapes)
                {
                    if (shape.Content is Label)
                    {       //generate title
                        GenerateSlideTitle((Label)shape.Content, ppSlide);
                    }
                    else if (shape.Content is Image)
                    {
                        GenerateImage((Image)shape.Content, ppSlide, shapes.IndexOf(shape));

                    }
                    else
                    {                            //generate chart
                        GenerateSlideChart((Entities.Graph)shape.Content, ppSlide, shapes.IndexOf(shape));
                    }
                }
            }
        }

        private void GenerateImage(Image image, _Slide ppSlide, int shapeIndex)
        {

            ChartLocator chartLocator = new ChartLocator(SlideLayoutHelper.GetSlideLayout(ppSlide.Layout), shapeIndex);
            ppSlide.Shapes.AddPicture(image.Path.LocalPath, TriStateHelper.ConvertFromBoolean(image.LinkToFile),
                                      TriStateHelper.ConvertFromBoolean(image.SaveWithDocument),
                                      chartLocator.Left + image.Left, chartLocator.Top + image.Top,
                                      image.Width ?? chartLocator.Width,
                                      image.Height ?? chartLocator.Height);
        }

        private void GenerateTable(Entities.Graph graph, PowerPoint._Slide ppSlide, int index)
        {
            CategoryAxis categoryAxis = (CategoryAxis)graph.Axes.CategoryAxis;
            ChartLocator chartLocator = new ChartLocator(SlideLayoutHelper.GetSlideLayout(ppSlide.Layout), index);
            int totalRows = categoryAxis.Labels.Count + 1;
            int totalCols = graph.Series.Count + 1;

            int width = this.MeassureTableWidth(categoryAxis, graph.Series);
            int height = this.MeassureTableHeight(categoryAxis, graph.Series);

            ppSlide.Shapes.AddTable(totalRows, totalCols, chartLocator.Left, chartLocator.Top, width, height);
            FormatPPTable(graph, ppSlide.Shapes[index + 1].Table);
            //FormatPPTable(graph, table);
            GenerateTableColHeaders(graph, ppSlide.Shapes[index + 1].Table);
            GenerateTableRowHeaders(graph, ppSlide.Shapes[index + 1].Table);
            GenerateTableData(graph, ppSlide.Shapes[index + 1].Table);
        }

        private void FormatPPTable(Entities.Graph graph, PowerPoint.Table table)
        {
            SeriesAxis seriesAxis = (SeriesAxis)graph.Axes.SeriesAxis;
            if (table != null)
            {
                for (int i = 1; i <= table.Rows.Count; i++)
                {
                    table.Rows[i].Height = 40;
                    for (int j = 1; j <= table.Columns.Count; j++)
                    {
                        if (i == 1 || j == 1)
                        {                     //headers
                            table.Rows[i].Cells[j].Shape.TextFrame.VerticalAnchor = MsoVerticalAnchor.msoAnchorMiddle;
                        }
                        else
                        {                                    //data
                            table.Rows[i].Cells[j].Shape.TextFrame.TextRange.Font.Name = seriesAxis.FontName;
                            table.Rows[i].Cells[j].Shape.TextFrame.TextRange.ParagraphFormat.Alignment = Microsoft.Office.Interop.PowerPoint.PpParagraphAlignment.ppAlignCenter;
                            table.Rows[i].Cells[j].Shape.TextFrame.VerticalAnchor = MsoVerticalAnchor.msoAnchorMiddle;
                            table.Rows[i].Cells[j].Shape.TextFrame.TextRange.Font.Size = seriesAxis.FontSize;
                        }
                    }
                }
            }
        }

        private void GenerateTableColHeaders(Entities.Graph graph, PowerPoint.Table table)
        {
            CategoryAxis categoryAxis = (CategoryAxis)graph.Axes.CategoryAxis;
            if (categoryAxis.Labels[0] != null && categoryAxis.Labels[0].CellWidth.HasValue)
                table.Columns[1].Width = categoryAxis.Labels[0].CellWidth.Value;

            for (int i = 0; i < graph.Series.Count; i++)
            {
                string colHeader = graph.Series[i].Title.Text;
                table.Rows[1].Cells[i + 2].Shape.TextFrame.TextRange.Text = colHeader;
                table.Rows[1].Cells[i + 2].Shape.TextFrame.TextRange.ParagraphFormat.Alignment =
                    Entities.Util.ParseEnum<Microsoft.Office.Interop.PowerPoint.PpParagraphAlignment>(
                        graph.Series[i].Title.HorizontalAlignment);
                table.Rows[1].Cells[i + 2].Shape.TextFrame.TextRange.Font.Color.RGB = (int)graph.Series[i].Title.Color;
                table.Rows[1].Cells[i + 2].Shape.TextFrame.TextRange.Font.Size = graph.Series[i].Title.FontSize;
                table.Rows[1].Cells[i + 2].Shape.TextFrame.TextRange.Font.Name = graph.Series[i].Title.FontName;
                table.Rows[1].Cells[i + 2].Shape.TextFrame.TextRange.Font.Bold = TriStateHelper.ConvertFromBoolean(graph.Series[i].Title.IsFontBold);
                table.Rows[1].Cells[i + 2].Shape.TextFrame.TextRange.Font.Italic = TriStateHelper.ConvertFromBoolean(graph.Series[i].Title.IsFontItalic);
                //size
                if (graph.Series[i].CellWidth.HasValue)
                    table.Columns[i + 2].Width = graph.Series[i].CellWidth.Value;
            }
        }

        private void GenerateTableRowHeaders(Entities.Graph graph, PowerPoint.Table table)
        {
            if (graph.Series[0] != null && graph.Series[0].CellHeight.HasValue)
                table.Rows[1].Height = graph.Series[0].CellHeight.Value;

            CategoryAxis categoryAxis = (CategoryAxis)graph.Axes.CategoryAxis;
            for (int i = 0; i < categoryAxis.Labels.Count; i++)
            {
                string colHeader = categoryAxis.Labels[i].Text;
                table.Rows[i + 2].Cells[1].Shape.TextFrame.TextRange.Text = colHeader;
                table.Rows[i + 2].Cells[1].Shape.TextFrame.TextRange.ParagraphFormat.Alignment =
                    Entities.Util.ParseEnum<Microsoft.Office.Interop.PowerPoint.PpParagraphAlignment>(categoryAxis.Labels[i].HorizontalAlignment);
                table.Rows[i + 2].Cells[1].Shape.TextFrame.TextRange.Font.Color.RGB = (int)categoryAxis.Labels[i].Color;
                table.Rows[i + 2].Cells[1].Shape.TextFrame.TextRange.Font.Size = categoryAxis.Labels[i].FontSize;
                table.Rows[i + 2].Cells[1].Shape.TextFrame.TextRange.Font.Name = categoryAxis.Labels[i].FontName;
                table.Rows[i + 2].Cells[1].Shape.TextFrame.TextRange.Font.Bold = TriStateHelper.ConvertFromBoolean(categoryAxis.Labels[i].IsFontBold);
                table.Rows[i + 2].Cells[1].Shape.TextFrame.TextRange.Font.Italic = TriStateHelper.ConvertFromBoolean(categoryAxis.Labels[i].IsFontItalic);
                //size
                if (categoryAxis.Labels[i].CellHeight.HasValue)
                    table.Rows[i + 2].Height = categoryAxis.Labels[i].CellHeight.Value;
            }
        }

        private void GenerateTableData(Entities.Graph graph, PowerPoint.Table table)
        {
            CategoryAxis categoryAxis = (CategoryAxis)graph.Axes.CategoryAxis;
            ValueAxis valueAxis = (ValueAxis)graph.Axes.ValueAxis;
            for (int i = 0; i < graph.Series.Count; i++)
            {
                for (int j = 0; j < categoryAxis.Labels.Count; j++)
                {
                    if (!graph.Series[i].Points[j].UseText)
                    {
                        double data = graph.Series[i].Points[j].Value;
                        string dataFormat = string.Format("{0}{1}##0{2}{3}",
                            graph.Series[i].Points.NegativePrefix, graph.Series[i].Points.CurrencyString,
                            !String.IsNullOrEmpty(graph.Series[i].Points.DecimalSpaces) ? "." + graph.Series[i].Points.DecimalSpaces : null,
                            graph.Series[i].Points.HasPercentSufix ? graph.Series[i].Points.PercentSufix : null);
                        table.Columns[i + 2].Cells[j + 2].Shape.TextFrame.TextRange.Text = data.ToString(dataFormat);
                    }
                    else
                    {
                        string data = graph.Series[i].Points[j].Label.Text;
                        table.Columns[i + 2].Cells[j + 2].Shape.TextFrame.TextRange.Text = data;
                    }
                    table.Columns[i + 2].Cells[j + 2].Shape.TextFrame.TextRange.ParagraphFormat.Alignment =
                    Entities.Util.ParseEnum<Microsoft.Office.Interop.PowerPoint.PpParagraphAlignment>(graph.Series[i].Points[j].HorizontalAlignment);
                    FormatTableCellFont(table.Columns[i + 2].Cells[j + 2].Shape.TextFrame.TextRange,
                                        graph.Series[i].Points, graph.Series[i].Points[j]);
                }
            }
        }

        private void FormatTableCellFont(PowerPoint.TextRange textRange, PointCollection pointCollection, Point point)
        {
            //compare agains default values.
            //TODO: set default values to public 
            if (point.FontName != string.Empty)
                textRange.Font.Name = point.FontName;
            else
                textRange.Font.Name = pointCollection.FontName;

            if (point.FontSize.HasValue)
                textRange.Font.Size = point.FontSize.Value;
            else
                textRange.Font.Size = pointCollection.FontSize;

            if (point.IsFontBold.HasValue)
                textRange.Font.Bold = TriStateHelper.ConvertFromBoolean(point.IsFontBold.Value);
            else
                textRange.Font.Bold = TriStateHelper.ConvertFromBoolean(pointCollection.IsFontBold);

            if (point.IsFontItalic.HasValue)
                textRange.Font.Italic = TriStateHelper.ConvertFromBoolean(point.IsFontItalic.Value);
            else
                textRange.Font.Italic = TriStateHelper.ConvertFromBoolean(pointCollection.IsFontItalic);

            if (point.IsFontUnderline.HasValue)
                textRange.Font.Underline = TriStateHelper.ConvertFromBoolean(point.IsFontUnderline.Value);
            else
                textRange.Font.Underline = TriStateHelper.ConvertFromBoolean(pointCollection.IsFontUnderline);

            //for color: label takes precedence, then point, and finally point collection
            if (point.UseText && point.Label.Color > 0)
                textRange.Font.Color.RGB = (int)point.Label.Color;
            else if (point.Color > 0)
                textRange.Font.Color.RGB = (int)point.Color;
            else
                textRange.Font.Color.RGB = (int)pointCollection.Color;
        }

        private void GenerateSlideTitle(Label title, PowerPoint._Slide ppSlide)
        {
            if (title.IsVisible)
            {
                PowerPoint.TextRange objTextRng = ppSlide.Shapes[1].TextFrame.TextRange;
                objTextRng.Text = title.Text;
                objTextRng.ParagraphFormat.Alignment =
                    Entities.Util.ParseEnum<Microsoft.Office.Interop.PowerPoint.PpParagraphAlignment>(title.HorizontalAlignment);
                objTextRng.Font.Name = title.FontName;
                objTextRng.Font.Size = title.FontSize;
                objTextRng.Font.Bold = Util.TriStateHelper.ConvertFromBoolean(title.IsFontBold);
                objTextRng.Font.Italic = Util.TriStateHelper.ConvertFromBoolean(title.IsFontItalic);
                objTextRng.Font.Underline = Util.TriStateHelper.ConvertFromBoolean(title.IsFontUnderline);
                objTextRng.Font.Color.RGB = (int)title.Color;
            }
            else
            {
                if ((ppSlide.Layout != Microsoft.Office.Interop.PowerPoint.PpSlideLayout.ppLayoutBlank) ||
                   (ppSlide.Layout != Microsoft.Office.Interop.PowerPoint.PpSlideLayout.ppLayoutLargeObject))
                {
                    ppSlide.Shapes[1].Delete();
                }
            }
        }

        private void GenerateSlideChart(Entities.Graph graph, PowerPoint._Slide ppSlide, int index)
        {
            if (graph != null)
            {
                if (graph.Type == ChartType.xlTableOnly)
                {
                    //ClearShapeSpace(ppSlide);
                    GenerateTable(graph, ppSlide, index);
                }
                else
                {
                    Graph.Chart objChart = GenerateOLEChart(ppSlide, index, Entities.Util.ParseEnum<XlChartType>(graph.Type));
                    GenerateChartTitle(graph, objChart);
                    GenerateLegend(graph, objChart);
                    GenerateDataTable(graph, objChart);
                    GenerateAxes(graph.Axes, objChart);
                    GenerateSeriesCollection(graph.Series, objChart, ((Entities.CategoryAxis)graph.Axes.CategoryAxis).Labels.Count);

                    if (objChart.ChartType == Microsoft.Office.Interop.Graph.XlChartType.xlLine || objChart.ChartType == Microsoft.Office.Interop.Graph.XlChartType.xlLineMarkers)
                    {
                        CategoryAxis categories = (CategoryAxis)graph.Axes.CategoryAxis;
                        for (int i = 0; i < categories.Labels.Count; i++)
                        {
                            CategoryLabel label = categories.Labels[i];
                            GenerateSeriesLine(label, objChart, i);
                        }
                        objChart.Application.Update();
                    }
                }
            }
        }

        private Graph.Chart GenerateOLEChart(PowerPoint._Slide ppSlide, int index, XlChartType type)
        {
            ChartLocator chartLocator = new ChartLocator(SlideLayoutHelper.GetSlideLayout(ppSlide.Layout), index);
            var chart = ppSlide.Shapes.AddChart(type, chartLocator.Left, chartLocator.Top, chartLocator.Width, chartLocator.Height);
            chart.
            return null;
        }

        private void GenerateChartTitle(Entities.Graph graph, Graph.Chart chart)
        {
            chart.HasTitle = graph.Title.IsVisible;

            if (graph.Title != null && graph.Title.IsVisible)
            {
                chart.ChartTitle.Text = graph.Title.Text;
                chart.ChartTitle.HorizontalAlignment =
                    Entities.Util.ParseEnum<Microsoft.Office.Interop.PowerPoint.PpParagraphAlignment>(graph.Title.HorizontalAlignment);
                //chart.ChartTitle.Font.Name = graph.Title.FontName;
                //chart.ChartTitle.Font.Size = graph.Title.FontSize;
                chart.ChartTitle.Font.Italic = TriStateHelper.ConvertFromBoolean(graph.Title.IsFontItalic);
                chart.ChartTitle.Font.Bold = TriStateHelper.ConvertFromBoolean(graph.Title.IsFontBold);
                //chart.ChartTitle.Font.Underline = TriStateHelper.ConvertFromBoolean(graph.Title.IsFontUnderline);
                chart.ChartTitle.Font.Color = graph.Title.Color;
            }
        }

        private void GenerateLegend(Entities.Graph graph, Graph.Chart chart)
        {
            chart.HasLegend = graph.Legend.IsVisible;
            if (graph.Legend != null && graph.Legend.IsVisible)
            {
                chart.Legend.Position = XlLegendPositionHelper.GetXLLengendPosition(graph.Legend.Position);
                chart.Legend.Font.Name = graph.Legend.FontName;
                chart.Legend.Font.Size = graph.Legend.FontSize;
                chart.Legend.Font.Italic = TriStateHelper.ConvertFromBoolean(graph.Legend.IsFontItalic);
                chart.Legend.Font.Bold = TriStateHelper.ConvertFromBoolean(graph.Legend.IsFontBold);
                //underline not available for legends
            }
        }

        private void GenerateDataTable(Entities.Graph graph, Graph.Chart chart)
        {
            if (graph.TableData != null && graph.TableData.IsVisible)
            {
                chart.HasDataTable = true;
                chart.DataTable.ShowLegendKey = graph.TableData.IsLegendKeyVisible;
            }
        }

        private void GenerateAxes(Entities.Axes axes, Graph.Chart chart)
        {
            if (axes != null)
            {
                GenerateValueAxis((Entities.ValueAxis)axes.ValueAxis, chart);
                GenerateCategoryAxis((Entities.CategoryAxis)axes.CategoryAxis, chart);
                GenerateSeriesAxis((Entities.SeriesAxis)axes.SeriesAxis, chart);
            }
        }

        private void GenerateValueAxis(Entities.ValueAxis valueAxis, Graph.Chart chart)
        {
            if (valueAxis != null)
            {
                Graph.Axis vAxis = (Graph.Axis)chart.Axes(Graph.XlAxisType.xlValue, Graph.XlAxisGroup.xlPrimary);

                if (valueAxis.Title != null && valueAxis.Title.IsVisible)
                {
                    vAxis.HasTitle = true;
                    vAxis.AxisTitle.Text = valueAxis.Title.Text;
                    vAxis.AxisTitle.HorizontalAlignment =
                    Entities.Util.ParseEnum<Microsoft.Office.Interop.PowerPoint.PpParagraphAlignment>(valueAxis.Title.HorizontalAlignment);
                    vAxis.AxisTitle.Font.Name = valueAxis.Title.FontName;
                    vAxis.AxisTitle.Font.Size = valueAxis.Title.FontSize;
                    vAxis.AxisTitle.Font.Bold = TriStateHelper.ConvertFromBoolean(valueAxis.Title.IsFontBold);
                    vAxis.AxisTitle.Font.Italic = TriStateHelper.ConvertFromBoolean(valueAxis.Title.IsFontItalic);
                    vAxis.AxisTitle.Font.Color = valueAxis.Title.Color;
                }
                if (valueAxis.Max != null && valueAxis.Max.IsEnabled)
                {
                    vAxis.MaximumScale = valueAxis.Max.Value;
                    vAxis.MaximumScaleIsAuto = false;
                }
                if (valueAxis.Min != null && valueAxis.Min.IsEnabled)
                {
                    vAxis.MinimumScale = valueAxis.Min.Value;
                    vAxis.MinimumScaleIsAuto = false;

                    //disable negative prefix if min < 0 in order to avoid a double dash --
                    if (valueAxis.Min.Value < 0)
                        valueAxis.HasNegativePrefix = false;
                }
                if (valueAxis.Scale != null && valueAxis.Scale.IsEnabled)
                {
                    vAxis.MajorUnit = valueAxis.Scale.Value;
                    vAxis.MajorUnitIsAuto = false;
                }

                if (valueAxis.MajorGrid.IsVisible)
                {
                    vAxis.HasMajorGridlines = true;
                    vAxis.MajorGridlines.Border.LineStyle = (int)valueAxis.MajorGrid.Line.Style;
                    vAxis.MajorGridlines.Border.Weight = (int)valueAxis.MajorGrid.Line.Weight;
                    vAxis.MajorGridlines.Border.Color = valueAxis.MajorGrid.Line.Color;
                }
                else
                {
                    vAxis.MajorGridlines.Delete();
                }

                vAxis.TickLabels.NumberFormat = string.Format("{0}{1}#{2}##0{3}{4}",
                    valueAxis.NegativePrefix, valueAxis.CurrencyString, valueAxis.ThousandsSeparator,
                    !String.IsNullOrEmpty(valueAxis.DecimalSpaces) ? "." + valueAxis.DecimalSpaces : null,
                    valueAxis.PercentSufix);

                vAxis.TickLabels.Font.Name = valueAxis.FontName;
                vAxis.TickLabels.Font.Size = valueAxis.FontSize;
                vAxis.TickLabels.Font.Bold = TriStateHelper.ConvertFromBoolean(valueAxis.IsFontBold);
                vAxis.TickLabels.Font.Italic = TriStateHelper.ConvertFromBoolean(valueAxis.IsFontItalic);
            }
        }

        private void GenerateCategoryAxis(Entities.CategoryAxis categoryAxis, Graph.Chart chart)
        {
            if (categoryAxis != null)
            {
                Graph.Axis vAxis = (Graph.Axis)chart.Axes(Graph.XlAxisType.xlCategory, Graph.XlAxisGroup.xlPrimary);
                vAxis.HasTitle = categoryAxis.Title.IsVisible;
                vAxis.TickLabelPosition = Microsoft.Office.Interop.Graph.XlTickLabelPosition.xlTickLabelPositionLow;
                if (categoryAxis.Title.IsVisible)
                {
                    vAxis.AxisTitle.Text = categoryAxis.Title.Text;
                    vAxis.AxisTitle.Font.Color = categoryAxis.Title.Color;
                    vAxis.AxisTitle.HorizontalAlignment =
                    Entities.Util.ParseEnum<Microsoft.Office.Interop.PowerPoint.PpParagraphAlignment>(categoryAxis.Title.HorizontalAlignment);
                    vAxis.AxisTitle.Font.Name = categoryAxis.Title.FontName;
                    vAxis.AxisTitle.Font.Size = categoryAxis.Title.FontSize;
                    vAxis.AxisTitle.Font.Bold = TriStateHelper.ConvertFromBoolean(categoryAxis.Title.IsFontBold);
                    vAxis.AxisTitle.Font.Italic = TriStateHelper.ConvertFromBoolean(categoryAxis.Title.IsFontItalic);
                }
                GenerateLabelCollection(categoryAxis.Labels, chart);

                vAxis.TickLabels.Font.Name = categoryAxis.FontName;
                vAxis.TickLabels.Font.Size = categoryAxis.FontSize;
                vAxis.TickLabels.Font.Bold = TriStateHelper.ConvertFromBoolean(categoryAxis.IsFontBold);
                vAxis.TickLabels.Font.Italic = TriStateHelper.ConvertFromBoolean(categoryAxis.IsFontItalic);
            }
        }

        private void GenerateLabelCollection(Entities.LabelCollection labelCollection, Graph.Chart chart)
        {
            ClearGraphCells(chart);
            if (labelCollection != null)
            {
                for (int i = 0; i < labelCollection.Count; i++)
                {
                    CategoryLabel label = labelCollection[i];
                    Graph.Range pointRange = (Graph.Range)chart.Application.DataSheet.Cells[i + 2, 1];
                    pointRange.set_Value(Graph.XlRangeValueDataType.xlRangeValueDefault, label.Text);
                }
            }
        }

        //TODO: Fix series axis label
        private void GenerateSeriesAxis(Entities.SeriesAxis seriesAxis, Graph.Chart chart)
        {
            //Graph.Axis vAxis = (Graph.Axis)chart.Axes(Graph.XlAxisType.xlSeriesAxis, Graph.XlAxisGroup.xlPrimary);
            //if (seriesAxis.Title != null && chart.ChartType == Microsoft.Office.Interop.Graph.XlChartType.xl3DColumn)
            //{
            //    vAxis.HasTitle = true;
            //    vAxis.AxisTitle.Text = seriesAxis.Title.Text;
            //}
        }

        private void GenerateSeriesCollection(Entities.SeriesCollection seriesCollection, Graph.Chart chart, int totalCategories)
        {
            if (seriesCollection != null)
            {
                for (int i = 0; i < seriesCollection.Count; i++)
                {
                    Series series = seriesCollection[i];
                    GenerateSeries(series, chart, i);
                }
            }
        }

        private void GenerateSeries(Entities.Series series, Graph.Chart chart, int index)
        {
            if (series != null)
            {
                //set series title (or x axis value)
                Graph.Range xRange = (Graph.Range)chart.Application.DataSheet.Cells[1, index + 2];
                xRange.set_Value(Graph.XlRangeValueDataType.xlRangeValueDefault, series.Title.Text);

                for (int i = 0; i < series.Points.Count; i++)
                {
                    Point point = series.Points[i];
                    if (point.Value.CompareTo(Double.NaN) != 0)
                    {
                        Graph.Range pointRange = (Graph.Range)chart.Application.DataSheet.Cells[i + 2, index + 2];
                        pointRange.set_Value(Graph.XlRangeValueDataType.xlRangeValueDefault, point.Value);
                    }
                }

                chart.Application.Update();
            }
        }

        private void GenerateSeriesLine(Entities.CategoryLabel line, Graph.Chart chart, int index)
        {
            Graph.Series a = (Graph.Series)chart.SeriesCollection(index + 1);
            if (chart.ChartType == Microsoft.Office.Interop.Graph.XlChartType.xlLineMarkers)
            {
                a.MarkerStyle = Entities.Util.ParseEnum<Microsoft.Office.Interop.Graph.XlMarkerStyle>(line.Marker.Style);
                a.MarkerSize = line.Marker.Size;
                //if xlMarkerStyleNone and one of the following values is set, the markerstyle will be reset to xlMarkerStyleAutomatic
                if (a.MarkerStyle != Microsoft.Office.Interop.Graph.XlMarkerStyle.xlMarkerStyleNone)
                {
                    a.MarkerBackgroundColor = (int)line.Marker.Background;
                    a.MarkerForegroundColor = (int)line.Marker.Foreground;
                }
            }
            a.Border.LineStyle = (int)line.Border.Style;
            a.Border.Weight = (int)line.Border.Weight;
            a.Border.Color = line.Border.Color;
            a.Smooth = line.IsSmooth;
        }

        private void ClearShapeSpace(PowerPoint._Slide ppSlide)
        {
            //HACK: VSTO 
            int limit = ppSlide.Shapes.Count;
            for (int i = limit; i >= 2; i--)
                ppSlide.Shapes[i].Delete();
            if (ppSlide.Layout == Microsoft.Office.Interop.PowerPoint.PpSlideLayout.ppLayoutLargeObject)
                ppSlide.Shapes[1].Delete();
        }

        private void ClearGraphCells(Graph.Chart chart)
        {
            chart.Application.DataSheet.Cells.Delete(null);
            chart.Application.Update();
        }

        private void NotifySlideComposing(int currentSlide, int totalSlides, SlideComposingEventArgs.ContentType type)
        {
            this.SlideComposing(this, new SlideComposingEventArgs(currentSlide, totalSlides, type));
        }

        private void NotifySlideCompose(bool isSuccessful)
        {
            this.SlideComposed(this, new SlideComposedEventArgs(isSuccessful));
        }

        private int MeassureTableHeight(CategoryAxis cAxis, Entities.SeriesCollection seriesCollection)
        {
            int height = 0;
            foreach (CategoryLabel label in cAxis.Labels)
            {
                if (label.CellHeight.HasValue)
                    height += label.CellHeight.Value;
            }
            //add first row size
            if (seriesCollection[0] != null && seriesCollection[0].CellHeight.HasValue)
                height += seriesCollection[0].CellHeight.Value;

            return height;
        }

        private int MeassureTableWidth(CategoryAxis cAxis, Entities.SeriesCollection seriesCollection)
        {
            int width = 0;
            foreach (Series series in seriesCollection)
            {
                if (series.CellWidth.HasValue)
                    width += series.CellWidth.Value;
            }
            //add first column width
            if (cAxis.Labels[0] != null && cAxis.Labels[0].CellWidth.HasValue)
            {
                width += cAxis.Labels[0].CellWidth.Value;
            }
            return width;
        }
    }
}
